<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="GSTZt" id="GSTZt"><span data-lake-id="u3a75319c" id="u3a75319c" style="color: rgb(85, 85, 85)">典型回答</span></h1>
  <p data-lake-id="u2a6b2702" id="u2a6b2702"><span data-lake-id="u1fc40164" id="u1fc40164">负载(load)是Linux机器的一个重要指标，直观了反应了机器当前的状态。</span></p>
  <p data-lake-id="ue34f733d" id="ue34f733d"><br></p>
  <p data-lake-id="u8d68b966" id="u8d68b966"><span data-lake-id="uc5ba8d3c" id="uc5ba8d3c">在Linux系统中，系统负载是对当前CPU工作量的度量，被定义为特定时间间隔内运行队列中的平均线程数。load average 表示机器一段时间内的平均load。这个值越低越好。负载过高会导致机器无法处理其他请求及操作，甚至导致死机。</span></p>
  <p data-lake-id="u49c5e805" id="u49c5e805"><span data-lake-id="uf4deb131" id="uf4deb131">​</span><br></p>
  <p data-lake-id="u4f1870eb" id="u4f1870eb"><span data-lake-id="ue83e9fce" id="ue83e9fce">Linux的负载高，主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多，都将导致服务器负载的急剧攀升。</span></p>
  <p data-lake-id="u47dfe2ea" id="u47dfe2ea"><br></p>
  <h1 data-lake-id="jk1z1" id="jk1z1"><span data-lake-id="u117ac813" id="u117ac813">扩展知识</span></h1>
  <p data-lake-id="uab6f324f" id="uab6f324f"><br></p>
  <h2 data-lake-id="6cc279ba" id="6cc279ba"><span data-lake-id="ud60c604f" id="ud60c604f">查看机器负载</span></h2>
  <p data-lake-id="u50867841" id="u50867841"><br></p>
  <p data-lake-id="u4a5a3ce1" id="u4a5a3ce1"><span data-lake-id="uc4457d8a" id="uc4457d8a">在Linux机器上，有多个命令都可以查看机器的负载信息。其中包括</span><code data-lake-id="u565e7e0b" id="u565e7e0b"><span data-lake-id="u2eabf298" id="u2eabf298">uptime</span></code><span data-lake-id="u71aec5ca" id="u71aec5ca">、</span><code data-lake-id="u881854d5" id="u881854d5"><span data-lake-id="ueb05cc09" id="ueb05cc09">top</span></code><span data-lake-id="u29e07a75" id="u29e07a75">、</span><code data-lake-id="ud95d1bd4" id="ud95d1bd4"><span data-lake-id="ufa3d5541" id="ufa3d5541">w</span></code><span data-lake-id="u9e32b484" id="u9e32b484">等。</span></p>
  <p data-lake-id="uccd444df" id="uccd444df"><br></p>
  <h3 data-lake-id="0641fd86" id="0641fd86"><code data-lake-id="u19d01ae3" id="u19d01ae3"><span data-lake-id="u76113063" id="u76113063">uptime</span></code><span data-lake-id="uf7a31ab2" id="uf7a31ab2">命令</span></h3>
  <p data-lake-id="u55be2075" id="u55be2075"><br></p>
  <p data-lake-id="uafe69fdf" id="uafe69fdf"><code data-lake-id="uc1db5ce6" id="uc1db5ce6"><span data-lake-id="u9035e1e0" id="u9035e1e0">uptime</span></code><span data-lake-id="u4c0f7d7e" id="u4c0f7d7e">命令能够打印系统总共运行了多长时间和系统的平均负载。uptime命令可以显示的信息显示依次为：现在时间、系统已经运行了多长时间、目前有多少登陆用户、系统在过去的1分钟、5分钟和15分钟内的平均负载。</span></p>
  <p data-lake-id="u8c0c6fb9" id="u8c0c6fb9"><br></p>
  <pre lang="java"><code>
➜  ~ uptime
13:29  up 23:41, 3 users, load averages: 1.74 1.87 1.97
</code></pre>
  <p data-lake-id="u6bf4ab29" id="u6bf4ab29"><br></p>
  <p data-lake-id="u8a4cf835" id="u8a4cf835"><span data-lake-id="u8cb9a1c8" id="u8cb9a1c8">这行信息的后半部分，显示"load average"，它的意思是"系统的平均负荷"，里面有三个数字，我们可以从中判断系统负荷是大还是小。</span></p>
  <p data-lake-id="u347523c6" id="u347523c6"><br></p>
  <p data-lake-id="uf7a2a648" id="uf7a2a648"><code data-lake-id="ue2ad79ec" id="ue2ad79ec"><span data-lake-id="u5f3d57f8" id="u5f3d57f8">1.74 1.87 1.97</span></code><span data-lake-id="u1ed05f0b" id="u1ed05f0b"> 这三个数字的意思分别是1分钟、5分钟、15分钟内系统的平均负荷。我们一般表示为load1、load5、load15。</span></p>
  <p data-lake-id="u46aa68d9" id="u46aa68d9"><br></p>
  <h3 data-lake-id="79ad7ec9" id="79ad7ec9"><code data-lake-id="u63d78c0b" id="u63d78c0b"><span data-lake-id="u278ec7f2" id="u278ec7f2">w</span></code><span data-lake-id="ua19e59ce" id="ua19e59ce">命令</span></h3>
  <p data-lake-id="u767596a2" id="u767596a2"><br></p>
  <p data-lake-id="u9ad11565" id="u9ad11565"><span data-lake-id="u3e03b836" id="u3e03b836">w命令的主要功能其实是显示目前登入系统的用户信息。但是与who不同的是，w命令功能更加强大，w命令还可以显示：当前时间，系统启动到现在的时间，登录用户的数目，系统在最</span><strong><span data-lake-id="ub3b65e4a" id="ub3b65e4a">近1分钟、5分钟和15分钟的平均负载</span></strong><span data-lake-id="u9c044575" id="u9c044575">。然后是每个用户的各项数据，项目显示顺序如下：登录帐号、终端名称、远 程主机名、登录时间、空闲时间、JCPU、PCPU、当前正在运行进程的命令行。</span></p>
  <p data-lake-id="u52a40a46" id="u52a40a46"><br></p>
  <pre lang="java"><code>
➜  ~ w
14:08  up 23:41, 3 users, load averages: 1.74 1.87 1.97
USER     TTY      FROM              LOGIN@  IDLE WHAT
hollis   console  -                六14   23:40 -
hollis   s000     -                六14   20:24 -zsh
hollis   s001     -                六15       - w
</code></pre>
  <p data-lake-id="u1fbfcf16" id="u1fbfcf16"><br></p>
  <p data-lake-id="u6138c9d3" id="u6138c9d3"><span data-lake-id="ucb57e25b" id="ucb57e25b">从上面的</span><code data-lake-id="u44a5bd44" id="u44a5bd44"><span data-lake-id="u7a92d6d6" id="u7a92d6d6">w</span></code><span data-lake-id="u28c58a02" id="u28c58a02">命令的结果可以看到，当前系统时间是14:08，系统启动到现在经历了23小时41分钟，共有3个用户登录。系统在近1分钟、5分钟和15分钟的平均负载分别是</span><code data-lake-id="udfd4a8a0" id="udfd4a8a0"><span data-lake-id="u5d891968" id="u5d891968">1.74 1.87 1.97</span></code><span data-lake-id="u27d7902b" id="u27d7902b">。这和</span><code data-lake-id="u9eed0c33" id="u9eed0c33"><span data-lake-id="u74e927d2" id="u74e927d2">uptime</span></code><span data-lake-id="u1ce64ea0" id="u1ce64ea0">得到的结果相同。 下面还打印了一些登录的用户的各项数据，不详细介绍了。</span></p>
  <p data-lake-id="u8917fa08" id="u8917fa08"><br></p>
  <h3 data-lake-id="43fa1873" id="43fa1873"><code data-lake-id="uab6b4bb5" id="uab6b4bb5"><span data-lake-id="ue56a1220" id="ue56a1220">top</span></code><span data-lake-id="u0a730601" id="u0a730601">命令</span></h3>
  <p data-lake-id="u36483b77" id="u36483b77"><br></p>
  <p data-lake-id="u7c090a68" id="u7c090a68"><span data-lake-id="ub9039c2e" id="ub9039c2e">top命令是Linux下常用的性能分析工具，能够实时显示系统中各个进程的资源占用状况，类似于Windows的任务管理器。</span></p>
  <p data-lake-id="ue7af4ed9" id="ue7af4ed9"><br></p>
  <pre lang="java"><code>
➜  ~ top
Processes: 244 total, 3 running, 9 stuck, 232 sleeping, 1484 threads                                                                                                                               14:16:01
Load Avg: 1.74, 1.87, 1.97  CPU usage: 8.0% user, 6.79% sys, 85.19% idle   SharedLibs: 116M resident, 16M data, 14M linkedit. MemRegions: 66523 total, 2152M resident, 50M private, 930M shared.
PhysMem: 7819M used (1692M wired), 370M unused. VM: 682G vsize, 533M framework vsize, 6402060(0) swapins, 7234356(0) swapouts. Networks: packets: 383006/251M in, 334448/60M out.
Disks: 1057821/38G read, 350852/40G written.

PID    COMMAND      %CPU TIME     #TH   #WQ  #PORT MEM    PURG   CMPRS  PGRP  PPID  STATE    BOOSTS          %CPU_ME %CPU_OTHRS UID  FAULTS    COW    MSGSENT   MSGRECV   SYSBSD    SYSMACH   CSW
30845  top          3.0  00:00.49 1/1   0    21    3632K  0B     0B     30845 1394  running  *0[1]           0.00000 0.00000    0    3283+     112    203556+   101770+   8212+     119901+   823+
30842  Google Chrom 0.0  00:47.39 17    0    155   130M   0B     0B     1146  1146  sleeping *0[1]           0.00000 0.00000    501  173746    2697   117678    37821     364228    444830    310043
</code></pre>
  <p data-lake-id="u5f33b3a8" id="u5f33b3a8"><br></p>
  <p data-lake-id="u94be4830" id="u94be4830"><span data-lake-id="u91c5b579" id="u91c5b579">上面的输出结果中，Load Avg: 1.74, 1.87, 1.97显示的就是负载信息。</span></p>
  <p data-lake-id="u5f5a9818" id="u5f5a9818"><br></p>
  <h2 data-lake-id="6dd3e079" id="6dd3e079"><span data-lake-id="ube25404b" id="ube25404b">机器正常负载范围</span></h2>
  <p data-lake-id="u474fb6a7" id="u474fb6a7"><br></p>
  <p data-lake-id="u34132ef9" id="u34132ef9"><span data-lake-id="udd4e68e9" id="udd4e68e9">对于机器的Load到底多少算正常的问题，一直都是很有争议的，不同人有着不同的理解。对于单个CPU，有人认为如果Load超过0.7就算是超出正常范围了。也有人认为只要不超过1都没问题。也有人认为，单个CPU的负载在2以下都可以接受。</span></p>
  <p data-lake-id="udef07082" id="udef07082"><br></p>
  <p data-lake-id="udb8feadc" id="udb8feadc"><span data-lake-id="u69b5f6e2" id="u69b5f6e2">为什么会有这么多不同的理解呢，是因为不同的机器除了CPU影响之外还有其他因素的影响，运行的程序、机器内存、甚至是机房温度等都有可能有区别。</span></p>
  <p data-lake-id="ub6a35843" id="ub6a35843"><br></p>
  <p data-lake-id="u2cb126bc" id="u2cb126bc"><span data-lake-id="u4fb21540" id="u4fb21540">比如，有些机器用于定时执行大量的跑批任务，这个时间段内，Load可能会飙的比较高。而其他时间可能会比较低。那么这段飙高时间我们要不要去排查问题呢？</span></p>
  <p data-lake-id="u38318e5d" id="u38318e5d"><br></p>
  <p data-lake-id="u9dff4a13" id="u9dff4a13"><span data-lake-id="u6757f466" id="u6757f466">我的建议是，最好根据自己机器的实际情况，建立一个指标的基线（如近一个月的平均值），只要日常的load在基线上下范围内不太大都可以接收，如果差距太多可能就要人为介入检查了。</span></p>
  <p data-lake-id="u3db3143a" id="u3db3143a"><br></p>
  <p data-lake-id="ub0bc589f" id="ub0bc589f"><span data-lake-id="uddfff5ed" id="uddfff5ed">但是，总要有个建议的阈值吧，关于这个值。阮一峰在自己的博客中有过以下建议：</span></p>
  <p data-lake-id="u54dd9a54" id="u54dd9a54"><br></p>
  <blockquote data-lake-id="ub9dae437" id="ub9dae437">
   <p data-lake-id="u7461928d" id="u7461928d"><span data-lake-id="u14ef6e35" id="u14ef6e35">当系统负荷持续大于0.7，你必须开始调查了，问题出在哪里，防止情况恶化。</span></p>
   <p data-lake-id="u846a16e4" id="u846a16e4"><span data-lake-id="u40440d06" id="u40440d06"> </span></p>
   <p data-lake-id="u85cb0669" id="u85cb0669"><span data-lake-id="u76b82769" id="u76b82769">当系统负荷持续大于1.0，你必须动手寻找解决办法，把这个值降下来。</span></p>
   <p data-lake-id="u78761b1e" id="u78761b1e"><span data-lake-id="u2c996994" id="u2c996994"> </span></p>
   <p data-lake-id="ue9380cd0" id="ue9380cd0"><span data-lake-id="u5cdb9739" id="u5cdb9739">当系统负荷达到5.0，就表明你的系统有很严重的问题，长时间没有响应，或者接近死机了。你不应该让系统达到这个值。</span></p>
  </blockquote>
  <p data-lake-id="ua1441bde" id="ua1441bde"><br></p>
  <p data-lake-id="ube4fe47e" id="ube4fe47e"><span data-lake-id="u7f2cd8d3" id="u7f2cd8d3">以上指标都是基于单CPU的，但是现在很多电脑都是多核的。所以，对一般的系统来说，是根据cpu数量去判断系统是否已经过载（Over Load）的。如果我们认为0.7算是单核机器负载的安全线的话，那么四核机器的负载最好保持在3(4*0.7 = 2.8)以下。</span></p>
  <p data-lake-id="u5f70e455" id="u5f70e455"><br></p>
  <p data-lake-id="u4d77a781" id="u4d77a781"><span data-lake-id="u2471a625" id="u2471a625">还有一点需要提一下，在Load Avg的指标中，有三个值，1分钟系统负荷、5分钟系统负荷，15分钟系统负荷。我们在排查问题的时候也是可以参考这三个值的。</span></p>
  <p data-lake-id="ua34eb000" id="ua34eb000"><br></p>
  <p data-lake-id="ube1673d5" id="ube1673d5"><span data-lake-id="u742c3e0c" id="u742c3e0c">一般情况下，1分钟系统负荷表示最近的暂时现象。15分钟系统负荷表示是持续现象，并非暂时问题。如果load15较高，而load1较低，可以认为情况有所好转。反之，情况可能在恶化。</span></p>
  <p data-lake-id="ucda4f5bb" id="ucda4f5bb"><br></p>
  <h2 data-lake-id="e7ba61e3" id="e7ba61e3"><span data-lake-id="uf0fb829d" id="uf0fb829d">如何降低负载</span></h2>
  <p data-lake-id="u606a051c" id="u606a051c"><br></p>
  <p data-lake-id="u86ffa4b5" id="u86ffa4b5"><span data-lake-id="u090e2ca0" id="u090e2ca0">导致负载高的原因可能很复杂，有可能是硬件问题也可能是软件问题。</span></p>
  <p data-lake-id="uba8651fc" id="uba8651fc"><br></p>
  <p data-lake-id="u71a5883f" id="u71a5883f"><span data-lake-id="u60693de0" id="u60693de0">如果是硬件问题，那么说明机器性能确实就不行了，那么解决起来很简单，直接换机器就可以了。</span></p>
  <p data-lake-id="u89f39b04" id="u89f39b04"><br></p>
  <p data-lake-id="ue1517cc5" id="ue1517cc5"><span data-lake-id="u98990928" id="u98990928">前面我们提过，CPU使用、内存使用、IO消耗都可能导致负载高。如果是软件问题，有可能由于Java中的某些线程被长时间占用、大量内存持续占用等导致。建议从以下几个方面排查代码问题：</span></p>
  <p data-lake-id="ud34b948e" id="ud34b948e"><br></p>
  <p data-lake-id="ud9e6ebc7" id="ud9e6ebc7"><span data-lake-id="u880c7472" id="u880c7472">1、是否有内存泄露导致频繁GC </span></p>
  <p data-lake-id="u237c00f3" id="u237c00f3"><span data-lake-id="u0b217b1b" id="u0b217b1b">2、是否有死锁发生 </span></p>
  <p data-lake-id="u0ff5834e" id="u0ff5834e"><span data-lake-id="ua8286b85" id="ua8286b85">3、是否有大字段的读写 </span></p>
  <p data-lake-id="u189d3b09" id="u189d3b09"><span data-lake-id="ud089c7e6" id="ud089c7e6">4、会不会是数据库操作导致的，排查SQL语句问题。</span></p>
  <p data-lake-id="u3c905c96" id="u3c905c96"><br></p>
  <p data-lake-id="uae47e9d6" id="uae47e9d6"><span data-lake-id="uabc0edf5" id="uabc0edf5">这里还有个建议，如果发现线上机器Load飙高，可以考虑先把堆栈内存dump下来后，进行重启，暂时解决问题，然后再考虑回滚和排查问题。</span></p>
  <p data-lake-id="u55af884d" id="u55af884d"><br></p>
  <h2 data-lake-id="1f5fa991" id="1f5fa991"><span data-lake-id="u7755d2fb" id="u7755d2fb">Java Web应用Load飙高排查思路</span></h2>
  <p data-lake-id="u217566c7" id="u217566c7"><br></p>
  <p data-lake-id="u394d60aa" id="u394d60aa"><span data-lake-id="u23efe7fd" id="u23efe7fd">1、使用uptime查看当前load，发现load飙高。</span></p>
  <p data-lake-id="u1ecbc004" id="u1ecbc004"><br></p>
  <pre lang="java"><code>
➜  ~ uptime
13:29  up 23:41, 3 users, load averages: 10 10 10
</code></pre>
  <p data-lake-id="ua05ae573" id="ua05ae573"><br></p>
  <p data-lake-id="u3218c731" id="u3218c731"><span data-lake-id="ue5b05826" id="ue5b05826">2、使用top命令，查看占用CPU较高的进程ID。</span></p>
  <p data-lake-id="u57d8d707" id="u57d8d707"><br></p>
  <pre lang="java"><code>
➜  ~ top

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
1893 admin     20   0 7127m 2.6g  38m S 181.7 32.6  10:20.26 java
</code></pre>
  <p data-lake-id="ue867cdac" id="ue867cdac"><br></p>
  <p data-lake-id="u91c5b311" id="u91c5b311"><span data-lake-id="u5a19df85" id="u5a19df85">发现PID为1893的进程占用CPU 181%。而且是一个Java进程，基本断定是软件问题。</span></p>
  <p data-lake-id="ub62ad84d" id="ub62ad84d"><br></p>
  <p data-lake-id="ud281fbe8" id="ud281fbe8"><span data-lake-id="u1d2e6765" id="u1d2e6765">3、使用 </span><code data-lake-id="u10b1d37a" id="u10b1d37a"><span data-lake-id="u806b17c5" id="u806b17c5">top</span></code><span data-lake-id="u6b206034" id="u6b206034">命令，查看具体是哪个线程占用率较高</span></p>
  <p data-lake-id="ue87132e3" id="ue87132e3"><br></p>
  <pre lang="java"><code>
➜  ~ top -Hp 1893
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
4519 admin     20   0 7127m 2.6g  38m R 18.6 32.6   0:40.11 java
</code></pre>
  <p data-lake-id="uae22b1fc" id="uae22b1fc"><br></p>
  <p data-lake-id="ube6f5d58" id="ube6f5d58"><span data-lake-id="ud35b483c" id="ud35b483c">4、使用</span><code data-lake-id="u07b74ea3" id="u07b74ea3"><span data-lake-id="ufa69eba2" id="ufa69eba2">printf</span></code><span data-lake-id="u07bee874" id="u07bee874">命令查看这个线程的16进制</span></p>
  <p data-lake-id="ua40ce7fc" id="ua40ce7fc"><br></p>
  <pre lang="java"><code>
➜  ~ printf %x 4519
11a7
</code></pre>
  <p data-lake-id="u73af147f" id="u73af147f"><br></p>
  <p data-lake-id="u31863980" id="u31863980"><span data-lake-id="u1a7cfe4d" id="u1a7cfe4d">5、使用</span><code data-lake-id="ufb713ae7" id="ufb713ae7"><span data-lake-id="u9c5dace9" id="u9c5dace9">jstack</span></code><span data-lake-id="ub98c5406" id="ub98c5406">命令查看当前线程正在执行的方法。</span></p>
  <p data-lake-id="ub1592711" id="ub1592711"><br></p>
  <pre lang="java"><code>
➜  ~ jstack 1893 |grep -A 200 11a7
"thread-5" #500 daemon prio=10 os_prio=0 tid=0x00007f632314a800 nid=0x11a2 runnable [0x000000005442a000]
java.lang.Thread.State: RUNNABLE
at sun.misc.URLClassPath$Loader.findResource(URLClassPath.java:684)
at sun.misc.URLClassPath.findResource(URLClassPath.java:188)
at java.net.URLClassLoader$2.run(URLClassLoader.java:569)
at java.net.URLClassLoader$2.run(URLClassLoader.java:567)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findResource(URLClassLoader.java:566)
at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248)
at com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)
</code></pre>
  <p data-lake-id="u7ebc25c5" id="u7ebc25c5"><br></p>
  <p data-lake-id="u34fba27c" id="u34fba27c"><span data-lake-id="uffb343da" id="uffb343da">从上面的线程的栈日志中，可以发现，当前占用CPU较高的线程正在执行我代码的com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)类。那么就可以去排查这个类是否用法有问题了。</span></p>
  <p data-lake-id="ub34eeab6" id="ub34eeab6"><br></p>
  <p data-lake-id="uf4d25762" id="uf4d25762"><span data-lake-id="u3be4b65f" id="u3be4b65f">6、还可以使用jstat来查看GC情况，看看是否有频繁FGC，然后再使用jmap来dump内存，查看是否存在内存泄露。</span></p>
 </body>
</html>